import { Frame } from './Frame';
import { View } from './View';

/**
 * Window class - Represents a main window in the Mini-XAF application.
 * Contains multiple Frames.
 */
export class Window {
  private _id: string;
  private _title: string;
  private _frames: Frame[] = [];
  private _activeFrame: Frame | null = null;

  /**
   * Create a new Window
   * @param id Window identifier
   * @param title Window title
   */
  constructor(id: string, title: string) {
    this._id = id;
    this._title = title;
  }

  /**
   * Get the window ID
   */
  public get id(): string {
    return this._id;
  }

  /**
   * Get the window title
   */
  public get title(): string {
    return this._title;
  }

  /**
   * Set the window title
   */
  public set title(value: string) {
    this._title = value;
  }

  /**
   * Get all frames in this window
   */
  public get frames(): Frame[] {
    return [...this._frames];
  }

  /**
   * Get the active frame
   */
  public get activeFrame(): Frame | null {
    return this._activeFrame;
  }

  /**
   * Create a new frame and add it to this window
   * @param id Frame identifier
   * @param title Frame title
   */
  public createFrame(id: string, title: string): Frame {
    const frame = new Frame(id, title);
    this._frames.push(frame);
    
    // If this is the first frame, set it as active
    if (this._frames.length === 1) {
      this._activeFrame = frame;
    }
    
    return frame;
  }

  /**
   * Add an existing frame to this window
   * @param frame The frame to add
   */
  public addFrame(frame: Frame): void {
    if (!this._frames.includes(frame)) {
      this._frames.push(frame);
      
      // If this is the first frame, set it as active
      if (this._frames.length === 1) {
        this._activeFrame = frame;
      }
    }
  }

  /**
   * Set the active frame
   * @param frame Frame to set as active
   */
  public setActiveFrame(frame: Frame): void {
    if (this._frames.includes(frame)) {
      this._activeFrame = frame;
    } else {
      throw new Error('Frame is not registered with this window');
    }
  }
  /**
   * Close a frame
   * @param frame Frame to close
   */
  public closeFrame(frame: Frame): void {
    const index = this._frames.indexOf(frame);
    if (index >= 0) {
      // First, determine which frame to activate next
      let nextActiveFrame: Frame | null = null;
      
      // If we're closing the active frame, decide which one to activate next
      if (this._activeFrame === frame) {
        // Try to activate the next frame to the right
        if (index < this._frames.length - 1) {
          nextActiveFrame = this._frames[index + 1];
        } 
        // If there's no frame to the right, try the one to the left
        else if (index > 0) {
          nextActiveFrame = this._frames[index - 1];
        }
        // Otherwise, we'll have no active frame
      }
      
      // Now remove the frame
      this._frames.splice(index, 1);
      
      // Set the new active frame if needed
      if (this._activeFrame === frame) {
        console.log(`Window.closeFrame: Setting new active frame: ${nextActiveFrame?.id || 'none'}`);
        this._activeFrame = nextActiveFrame;
      }
    }
  }/**
   * Navigate to a specific view
   * @param view The view to navigate to
   * @param options Optional navigation options
   */
  public navigate(view: View, options?: { frameId?: string; reuseFrame?: boolean }): Frame {
    if (!view) {
      console.error('Window.navigate: View cannot be null or undefined');
      throw new Error('View cannot be null or undefined');
    }

    console.log(`Window.navigate: Navigating to view: ${view.id} (type: ${view.constructor.name})`);
    let frame: Frame;

    // First, check if there's already a frame with the same view type and ID
    const existingFrameWithView = this._frames.find(f => 
      f.view && 
      f.view.id === view.id && 
      f.view.constructor.name === view.constructor.name
    );

    if (existingFrameWithView) {
      console.log(`Window.navigate: Found existing frame with the same view: ${existingFrameWithView.id}`);
      frame = existingFrameWithView;
      
      // Set active but don't replace the view to preserve state
      this.setActiveFrame(frame);
      
      // Make sure controllers are properly refreshed
      if (frame.view) {
        frame.view.controllers.forEach(controller => {
          controller.setView(frame.view!);
        });
      }
      
      return frame;
    }

    // Check if we should use a specific frame by ID
    if (options?.frameId) {
      console.log(`Window.navigate: Looking for existing frame with ID: ${options.frameId}`);
      const existingFrame = this._frames.find(f => f.id === options.frameId);
      if (existingFrame) {
        console.log(`Window.navigate: Found existing frame: ${existingFrame.id}`);
        frame = existingFrame;
      } else {
        // Create a new frame with the given ID
        console.log(`Window.navigate: Creating new frame with ID: ${options.frameId}`);
        frame = new Frame(options.frameId, view.caption || view.name);
        this.addFrame(frame);
      }
    } else if (options?.reuseFrame && this._activeFrame) {
      // Reuse the active frame only if explicitly requested
      console.log(`Window.navigate: Reusing active frame: ${this._activeFrame.id}`);
      frame = this._activeFrame;
    } else {
      // Use a consistent ID for frames with the same view type and ID
      // This makes it easier to find existing frames
      const frameId = `view_${view.constructor.name}_${view.id}`;
      
      // Check if we already have a frame with this ID
      const existingFrame = this._frames.find(f => f.id === frameId);
      if (existingFrame) {
        console.log(`Window.navigate: Found existing frame with ID: ${frameId}`);
        frame = existingFrame;
      } else {
        // Create a new frame with a consistent ID
        console.log(`Window.navigate: Creating new frame with ID: ${frameId}`);
        frame = new Frame(frameId, view.caption || view.name);
        this.addFrame(frame);
      }
    }

    // Set the view in the frame
    console.log(`Window.navigate: Setting view ${view.name} in frame ${frame.id}`);
    frame.view = view;
    frame.title = view.caption || view.name;
    
    // Set the frame as active
    console.log(`Window.navigate: Setting frame ${frame.id} as active`);
    this.setActiveFrame(frame);

    console.log(`Window.navigate: Navigation completed. Frame count: ${this._frames.length}`);
    return frame;
  }
}
